<body></body>

<script>
  const el = document.querySelector('button')
  function createRenderer(optios) {
    const {createElement, setElementText, insert} = optios
    //特殊处理：除了 input 能够js设置form是一个js设置dom，html类型只能看元素里面有没有
    function shouldSetAsProps(el, key, value) {
      if (key === 'form' && el.tagName === 'INPUT') return false
      return key in el
    }
    // patchProps：用于更新 DOM 元素的属性。根据属性的类型（DOM 属性或 HTML 属性）选择合适的设置方式。
    // 如果属性是 DOM 属性，则直接通过 el[key] 设置；DOM 属性 是浏览器解析和渲染页面后，
    // 所创建的 HTML 元素对象上的属性。DOM 属性是动态的，表示当前元素的状态或值，可以随时修改。
    // 如果属性是 HTML 属性，则使用 el.setAttribute 来设置。type 和 value这些属性静态表示 HTML中定义初始值
    function patchProps(el, key, value) {
      if (shouldSetAsProps(el, key, value)) {
        const type = typeof el[key] //  获取该 DOM 属性值 的类型
        if (type === 'boolean' && value === '') {
          el[key] = true // 如果是dom使用标准是布尔值，并且当前value是空，将值矫正为true
        } else {
          el[key] = value
        }
      } else {
        el.setAttribute(key, vnode.props[key])
      }
    }

    // 挂载
    function mountElement(vnode, container) {
      const el = createElement(vnode.type)

      if (typeof vnode.children === 'string') {
        setElementText(el, vnode.children) //元素是字符串，直接设置文本
      } else if (Array.isArray(vnode.children)) {
        vnode.children.forEach(child => {
          patch(null, child, el) // 子节点是数组，遍历child调用patch挂载他们
        })
      }

      if (vnode.props) {
        for (const key in vnode.props) {
          patchProps(el, key, vnode.props[key]) // 区分更新
        }
      }
      insert(el, container)
    }

    // patch
    function patch(n1, n2, container) {
      if (!n1) {
        mountElement(n2, container)
      } else {
        console.log('n1存在, 意味需要打补丁，暂时没做到')
      }
    }

    // 分支
    function render(vnode, container) {
      if (vnode) {
        patch(container._vnode, vnode, container)
      } else {
        if (container._vnode) container.innerHTML = ''
      }
      container._vnode = vnode
    }
    return {render}
  }

  // 渲染器
  const renderer = createRenderer({
    createElement(tag) {
      return document.createElement(tag)
    },
    setElementText(el, text) {
      el.textContent = text
    },
    insert(el, parent, anchor = null) {
      parent.insertBefore(el, anchor)
    }
  })

  const vnode = {
    type: 'form',
    props: {
      id: 'form1'
    },
    // 貌似不行，属性form的setAttribute设置不成功，需要当做js设置特殊处理
    children: [
      {
        type: 'input',
        props: {
          form: 'form1'
        }
      }
    ]
  }
  renderer.render(vnode, document.body)
  /*
  HTML 属性（如 input 元素的 value 属性）表示元素的初始值，应该通过 el.setAttribute() 来设置。
  DOM 属性（如 input.value）表示元素的当前状态，应该通过 el[key] 来设置。
  */
</script>
